/*****************************************************\
* Copyright (c) 2020 The game2d Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.

* Author:         dzlua - https://gitee.com/dzlua/game2d.git
* Email:          505544956@qq.com
* FileName:       core/sprite.hpp
* Create Time:    2020/03/19 18:52:52
* Description:    /
\****************************************************/
#ifndef __GAME2D_CORE_SPRITE_H__
#define __GAME2D_CORE_SPRITE_H__

#include "game2d.h"
#include "utils/utils.h"

namespace g2d {
  class Sprite : public GameObject {
    public:
      Sprite(bool load_res_on_enter) : GameObject(load_res_on_enter) {
        memset(&rect_, 0, sizeof(rect_));
        memset(&back_color_, 0, sizeof(back_color_));
        tile_data_ = 0;
      }
      virtual ~Sprite() = default;
    public:
      virtual void move(float dx, float dy) { rect_.x += dx; rect_.y += dy; }
      virtual void move_to(float x, float y) { rect_.x = x; rect_.y = y; }
      virtual void set_size(float w, float h) { rect_.w = w; rect_.h = h; }
      virtual void set_rect(float x, float y, float w, float h) {
        rect_.x = x; rect_.y = y; rect_.w = w; rect_.h = h;
      }
      virtual void set_rect(const SDL_FRect &rc) { rect_ = rc; }
      virtual const SDL_FRect& rect() const { return rect_; }
      virtual SDL_FPoint pos() const { SDL_FPoint pt; pt.x = rect_.x; pt.y = rect_.y; return std::move(pt); }
      virtual float width() const { return rect_.w; }
      virtual float height() const { return rect_.h; }
      virtual float left() const { return rect_.x; }
      virtual float top() const { return rect_.y; }
      virtual float right() const { return rect_.x + rect_.w; }
      virtual float bottom() const { return rect_.y + rect_.h; }
      virtual bool pt_in(float x, float y) const { return PtInRect(x,y,rect_); }
    public:
      virtual void set_back_color(const SDL_Color &color) { back_color_ = color; }
      virtual const SDL_Color& back_color() const { return back_color_; }
      virtual void set_image(TextureData *image) { image_ = *image; }
      virtual void set_image(const char *id, const SDL_Rect *src) {
        if (id) image_.id = id;
        if (src) image_.src = *src;
      }
      virtual const TextureData& image() const { return image_; }
      virtual void set_attribute(const char *name, const char *value);
    public:
      virtual void set_tile_data(int d, const char *id, const SDL_Rect *src) {
        tile_data_ = d;
        set_image(id, src);
      }
      virtual int tile_data() const { return tile_data_; }
    public:
      static bool PtInRect(float x, float y, const SDL_FRect &rc) {
        if (x<rc.x || x>rc.x+rc.w) return false;
        if (y<rc.y || y>rc.y+rc.h) return false;
        return true;
      }
    public:
      virtual void render(g2d::Renderer &r) override {
        if (!visible_) return;
        if (back_color_.a > 0) {
          r.set_draw_color(back_color_);
          r.fill_rect(&rect_);
        }
        if (!image_.id.empty())
          r.draw_texture(&image_, &rect_);
        GameObject::render(r);
      }
      virtual void doinit() {}
    protected:
      SDL_FRect rect_;
      SDL_Color back_color_;
      TextureData image_;
      int tile_data_;
  };

  class AniSprite : public Sprite {
    public:
      AniSprite(bool load_res_on_enter) : Sprite(load_res_on_enter) {
        time_interval_ = 0;
        time_last_ = 0;
        index_ = 0;
        start_frame_ = SDL_MAX_UINT32;
        stop_frame_ = SDL_MAX_UINT32;
        started_ = false;
      }
      virtual ~AniSprite() = default;
    public:
      virtual void set_interval(Uint32 interval) { time_interval_ = interval; }
      virtual Uint32 interval() const { return time_interval_; }
      virtual void set_start_frame(Uint32 frame) { start_frame_ = frame; }
      virtual Uint32 start_frame() const { return start_frame_; }
      virtual void set_stop_frame(Uint32 frame) { stop_frame_ = frame; }
      virtual Uint32 stop_frame() const { return stop_frame_; }
      virtual void set_cur_frame(Uint32 frame) { index_ = frame; }
      virtual Uint32 cur_frame() const { return index_; }
      virtual void set_image(const char *image, Uint32 rows, Uint32 cols, Uint32 w, Uint32 h) {
        if (!image || !*image || (rows == 0 && cols == 0)) return;
        image_.id = image;
        for (Uint32 j = 0; j < rows; ++j) {
          for (Uint32 i = 0; i < cols; ++i) {
            SDL_Rect rc;
            rc.x = i * w;
            rc.y = j * h;
            rc.w = w;
            rc.h = h;
            srcs_.push_back(std::move(rc));
          }
        }
      }
      virtual void start() { started_ = true; }
      virtual void stop() { started_ = false; }

      virtual void set_attribute(const char *name, const char *value);
    public:
      virtual void update(Input &inp, Audio &aud) override {
        if (!enabled_) return;
        if (!started_) return;
        if (srcs_.size() == 0) return;
        if (start_frame_ >= srcs_.size()) start_frame_ = 0;
        if (stop_frame_ >= srcs_.size()) stop_frame_ = srcs_.size() - 1;
        auto time = SDL_GetTicks() - time_last_;
        if (time > time_interval_) {
          ++index_;
          time_last_ = SDL_GetTicks();
        }
        if (index_ > stop_frame_) index_ = start_frame_;
      }
      virtual void render(g2d::Renderer &r) override {
        if (!visible_) return;
        if (image_.id.empty()) return;
        if (index_ >= srcs_.size()) return;
        r.draw_texture(image_.id.c_str(), &rect_, &srcs_[index_]);
      }
    protected:
      std::vector<SDL_Rect> srcs_;
      Uint32 time_interval_;
      Uint32 time_last_;
      Uint32 index_;
      Uint32 start_frame_;
      Uint32 stop_frame_;
      bool started_;
  };
} // end namespace g2d


#endif // __GAME2D_CORE_SPRITE_H__